package com.itheima.advantagesup.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.advantagesup.common.PageBean;
import com.itheima.advantagesup.dto.SysRoleDTO;
import com.itheima.advantagesup.entity.SysMenu;
import com.itheima.advantagesup.entity.SysRole;
import com.itheima.advantagesup.entity.SysRoleMenu;
import com.itheima.advantagesup.mapper.SysMenuMapper;
import com.itheima.advantagesup.mapper.SysRoleMapper;
import com.itheima.advantagesup.mapper.SysRoleMenuMapper;
import com.itheima.advantagesup.service.SysRoleService;
import com.itheima.advantagesup.vo.MenuVO;
import com.itheima.advantagesup.vo.SysRoleVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * SysRoleService
 *
 * @author liudo
 * @version 1.0
 * @project advantages-up
 * @date 2023/9/11 21:19:10
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl implements SysRoleService {

    private final SysRoleMapper sysRoleMapper;
    private final SysRoleMenuMapper sysRoleMenuMapper;
    private final SysMenuMapper sysMenuMapper;

    @Override
    public PageBean<SysRoleVO> list(Integer page, Integer limit, String name) {
        PageHelper.startPage(page, limit);
        SysRole sysRole = new SysRole();
        sysRole.setName(name);
        List<SysRole> sysRoles = sysRoleMapper.selectList(sysRole);
        PageInfo<SysRole> pageInfo = new PageInfo<>(sysRoles);
        List<SysRoleVO> sysRoleVOS = pageInfo.getList().stream().map(SysRole::covertToVO).collect(Collectors.toList());
        return PageBean.of(pageInfo.getTotal(), sysRoleVOS);
    }

    @Override
    public List<SysRoleVO> allData() {
        List<SysRole> sysRoles = sysRoleMapper.selectList(new SysRole());
        if (!CollectionUtils.isEmpty(sysRoles)) {
            return sysRoles.stream().map(SysRole::covertToVO).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysRoleDTO sysRoleDTO) {
        // 新增角色信息
        String roleId = UUID.randomUUID().toString();
        SysRole sysRole = new SysRole();
        sysRole.setId(roleId);
        sysRole.setName(sysRoleDTO.getName());
        sysRole.setDescription(sysRole.getDescription());
        sysRole.setCreateDate(new Date());
        sysRole.setUpdateDate(new Date());
        sysRole.setDelFlag("0");
        sysRoleMapper.insert(sysRole);
        // 新增角色和菜单关联信息
        List<Integer> menuids = sysRoleDTO.getMenuids();
        insertSysRoleMenuBatch(roleId, menuids);
    }

    @Override
    public SysRoleVO rowInfo(String id) {
        // 角色信息
        SysRole sysRole = sysRoleMapper.selectById(id);
        // 角色菜单列表信息
        List<SysMenu> sysMenuList = sysMenuMapper.selectListByRoleIds(Collections.singletonList(sysRole.getId()));
        // 将角色信息变成树状结构
        List<MenuVO> sysMenus = covertVOTree(sysMenuList);
        SysRoleVO sysRoleVO = sysRole.covertToVO();
        sysRoleVO.setAuthList(sysMenus);
        return sysRoleVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysRoleDTO sysRoleDTO) {
        SysRole sysRole = sysRoleMapper.selectById(sysRoleDTO.getId());
        if (Objects.isNull(sysRole)) {
            throw new RuntimeException("角色不存在");
        }
        String name = sysRoleDTO.getName();
        String description = sysRoleDTO.getDescription();
        List<Integer> menuids = sysRoleDTO.getMenuids();

        sysRole.setName(name);
        sysRole.setDescription(description);
        sysRole.setUpdateDate(new Date());
        sysRoleMapper.update(sysRole);
        // 角色权限更新
        sysRoleMenuMapper.deleteByRoleId(sysRole.getId());
        insertSysRoleMenuBatch(sysRole.getId(), menuids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        // 删除角色信息
        sysRoleMapper.deleteById(id);
        // 删除角色和菜单的关联信息
        sysRoleMenuMapper.deleteByRoleId(id);
    }

    /**
     * 转换成VO树状结构
     *
     * @param sysMenuList sys菜单列表
     * @return {@link List}<{@link MenuVO}>
     */
    private List<MenuVO> covertVOTree(List<SysMenu> sysMenuList) {
        // 获取顶层菜单的逻辑 就是pid为0
        List<MenuVO> topLayerMenus = sysMenuList.stream()
                .filter(sysMenu -> sysMenu.getPid() == 0)
                .map(SysMenu::transformVO)
                .collect(Collectors.toList());
        topLayerMenus.forEach(sysMenuItem1 -> {
            // 获取第一层的子集
            List<MenuVO> menus2 = sysMenuList.stream()
                    .filter(sysMenu -> sysMenu.getPid().equals(sysMenuItem1.getId()))
                    .map(SysMenu::transformVO)
                    .collect(Collectors.toList());

            menus2.forEach(sysMenuItem2 -> {
                // 获取第二层的子集
                List<MenuVO> menus3 = sysMenuList.stream()
                        .filter(sysMenu -> sysMenu.getPid().equals(sysMenuItem2.getId()))
                        .map(SysMenu::transformVO)
                        .collect(Collectors.toList());
                sysMenuItem2.setChildren(menus3);
            });

            sysMenuItem1.setChildren(menus2);
        });
        return topLayerMenus;
    }

    /**
     * 插入系统角色菜单批处理
     *
     * @param roleId  角色id
     * @param menuids 菜单ID
     */
    private void insertSysRoleMenuBatch(String roleId, List<Integer> menuids) {
        if (!CollectionUtils.isEmpty(menuids)) {
            List<SysRoleMenu> sysRoleMenuList = menuids.stream()
                    .map(menuid -> {
                        SysRoleMenu sysRoleMenu = new SysRoleMenu();
                        sysRoleMenu.setRoleId(roleId);
                        sysRoleMenu.setMenuId(menuid);
                        return sysRoleMenu;
                    }).collect(Collectors.toList());
            sysRoleMenuMapper.insertBatch(sysRoleMenuList);
        }
    }
}
